package com.photoeditor.demo.ui.widget.image.enlarge;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.PathEffect;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

import com.common.base.log.DLog;
import com.common.base.utils.DeviceUtils;
import com.photoeditor.R;

import java.util.ArrayList;

/**
 * Created by winn on 17/10/25.
 */

public class EnlargerView extends View {

    public static final int DEFAULT_PROGRESS = 40;

    public static final float SCALE_MAX = 2f;
    public static final float SCALE_MIN = 0.0f;

    public static final float SCALE = (SCALE_MAX - SCALE_MIN) * DEFAULT_PROGRESS / 100;
    public static final float RADIU = 0.1f;
    public static final float CENTER_X = 0.5f;
    public static final float CENTER_Y = 0.5f;
    public static final float CENTER_X_FIRST = 0.3f;
    public static final float CENTER_X_SECOND = 0.7f;

    private ArrayList<EnlargerBean> mBeanList;

    private Paint mPaint;
    private int mNormalPaintColor;
    private int mSelPaintColor;

    private boolean mIsChanged;

    private OnParamChangeListener mListener;

    private static final int MODE_NONE = 0;
    private static final int MODE_MOVE = 1;
    private static final int MODE_SCALE = 2;

    private int mMode = MODE_NONE;
    //单点touch down 的坐标
    private float mDownX;
    private float mDownY;
    //多点touch down 的坐标
    private float mMidX;
    private float mMidY;
    private float oldDist = 1f;
    private boolean mIsMoving = false;
    private boolean mClickBean = false;
    private int mSelectIndex = -1;
    private EnlargerBean mCurrentTouchBean;
    private Rect mLastRect = new Rect();

    public EnlargerView(Context context) {
        super(context);
        init();
    }

    public EnlargerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public EnlargerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStrokeWidth(DeviceUtils.dip2px(getContext(), 2));
        mPaint.setStyle(Paint.Style.STROKE);
        mNormalPaintColor = Color.WHITE;
        mSelPaintColor = getResources().getColor(R.color.accent_color);
        mPaint.setColor(mNormalPaintColor);
        PathEffect effects = new DashPathEffect(new float[]{DeviceUtils.dip2px(getContext(), 8), DeviceUtils.dip2px(getContext(), 4)}, 0);
        mPaint.setPathEffect(effects);
        mBeanList = new ArrayList<>();
    }

    public void addEnlarger(Rect rect) {
        mBeanList.add(new EnlargerBean(rect, SCALE));
    }

    public void addEnlarger(EnlargerBean bean) {
        mBeanList.add(bean);
    }

    public boolean isChanged() {
        return mIsChanged;
    }

    public void reset() {
        mIsChanged = false;
        mBeanList.clear();
        mCurrentTouchBean = null;
        mSelectIndex = -1;
    }

    public void onProgressChanged(int progress, boolean fromUser) {
        mIsChanged = true;
        if (mBeanList.size() == 1) {
            EnlargerBean bean = mBeanList.get(0);
            bean.setScale((SCALE_MAX - SCALE_MIN) * progress / 100);
        } else {
            EnlargerBean sel = getSelBean();
            // 如果当前没有选中，则同时进行scale操作，否则仅对选中进行scale
            if (sel != null) {
                sel.setScale((SCALE_MAX - SCALE_MIN) * progress / 100);
            } else {
                for (int i = 0; i < mBeanList.size(); ++i) {
                    EnlargerBean bean = mBeanList.get(i);
                    bean.setScale((SCALE_MAX - SCALE_MIN) * progress / 100);
                }
            }
        }
    }

    private EnlargerBean getSelBean() {
        EnlargerBean ret = null;
        for (int i = 0; i < mBeanList.size(); ++i) {
            EnlargerBean bean = mBeanList.get(i);
            if (bean.isIsSelected()) {
                ret = bean;
                break;
            }
        }
        return ret;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean ret = true;
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                mMode = MODE_NONE;
                mDownX = event.getX();
                mDownY = event.getY();
                mIsMoving = false;
                int touchIndex = getTouchIndex(event);
                if (touchIndex >= 0) {
                    if (mSelectIndex >= 0 && mSelectIndex < mBeanList.size()) {
                        mCurrentTouchBean = mBeanList.get(mSelectIndex);
                    }
                    if (mCurrentTouchBean != null) {
                        mCurrentTouchBean.setIsSelected(false);
                    }
                    mClickBean = true;
                    mSelectIndex = touchIndex;
                    mCurrentTouchBean = mBeanList.get(mSelectIndex);
                    mCurrentTouchBean.setIsSelected(true);
                    refresh();
                }
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                mMidX = (event.getX(0) + event.getX(1)) / 2;
                mMidY = (event.getY(0) + event.getY(1)) / 2;
                oldDist = spacing(event);
                if (mSelectIndex >= 0 && mSelectIndex < mBeanList.size()) {
                    mCurrentTouchBean = mBeanList.get(mSelectIndex);
                }
                if (mSelectIndex >= 0 && mSelectIndex < mBeanList.size() &&
                        checkCanOpt(event.getX(0), event.getY(0), event.getX(1), event.getY(1), mCurrentTouchBean.getRect())) {
                    mMode = MODE_SCALE;
                    mClickBean = true;
                    mCurrentTouchBean.setIsSelected(true);
                    mLastRect.set(mCurrentTouchBean.getRect());
                    refresh();
                    return true;
                } else {
                    float temp, dis = 0, dx, dy;
                    int tempIndex = -1;
                    for (int i = 0; i < mBeanList.size(); i++) {
                        dx = mBeanList.get(i).getRect().centerX() - mMidX;
                        dy = mBeanList.get(i).getRect().centerY() - mMidY;
                        temp = (float) Math.sqrt(dx * dx + dy * dy);
                        if (i == 0) {
                            dis = temp;
                            tempIndex = i;
                        }
                        if (temp < dis) {
                            dis = temp;
                            tempIndex = i;
                        }
                    }
                    if (mCurrentTouchBean != null) {
                        mCurrentTouchBean.setIsSelected(false);
                    }
                    if (tempIndex != -1 && checkCanOpt(event.getX(0), event.getY(0), event.getX(1), event.getY(1), mBeanList.get(tempIndex).getRect())) {
                        mMode = MODE_SCALE;
                        mClickBean = true;
                        mSelectIndex = tempIndex;
                        mCurrentTouchBean = mBeanList.get(mSelectIndex);
                        mCurrentTouchBean.setIsSelected(true);
                        mLastRect.set(mCurrentTouchBean.getRect());
                        refresh();
                        return true;
                    }
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (event.getPointerCount() > 1) {
                    float newDist = spacing(event);
                    if (mCurrentTouchBean == null || mClickBean && Math.abs(newDist - oldDist) <= ViewConfiguration.getTouchSlop()) {
                        return true;
                    }
                    mClickBean = false;
                    float scale = newDist / oldDist;
                    float nowMidX = (event.getX(0) + event.getX(1)) / 2;
                    float nowMidY = (event.getY(0) + event.getY(1)) / 2;
                    mCurrentTouchBean.move(nowMidX - mMidX, nowMidY - mMidY);
                    mCurrentTouchBean.scaleSize(scale);
                    mMidX = nowMidX;
                    mMidY = nowMidY;
                    oldDist = newDist;
                    refresh();
                    return true;
                } else {
                    if (mMode == MODE_SCALE) {
                        return false;
                    }
                    float nowX = event.getX();
                    float nowY = event.getY();
                    if (mCurrentTouchBean == null
                            || mClickBean && Math.abs(nowX - mDownX) <= ViewConfiguration.getTouchSlop() && Math.abs(nowY - mDownY) <= ViewConfiguration.getTouchSlop()) {
                        return false;
                    }
                    mIsMoving = true;
                    mClickBean = false;
                    mCurrentTouchBean.move(nowX - mDownX, nowY - mDownY);
                    mDownX = nowX;
                    mDownY = nowY;
                    refresh();
                    return true;
                }
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mCurrentTouchBean = null;
                break;
        }
        return ret;
    }

    private int getTouchIndex(MotionEvent event) {
        int ret = -1;
        for (int i = 0; i < mBeanList.size(); ++i) {
            EnlargerBean bean = mBeanList.get(i);
            if (bean.getRect().contains((int) event.getX(), (int) event.getY())) {
                ret = i;
                break;
            }
        }
        return ret;
    }

    // 触碰两点间距离
    private float spacing(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return (float) Math.sqrt(x * x + y * y);
    }

    //判断两点触控能否对目标操作
    private boolean checkCanOpt(float x1, float y1, float x2, float y2, Rect src) {
        if ((x1 < src.left && x2 < src.left) || (x1 > src.right && x2 > src.right)) {
            return false;
        }
        if ((y1 < src.top && y2 < src.top) || (y1 > src.bottom && y2 > src.bottom)) {
            return false;
        }
        return true;
    }

    private void refresh() {
        invalidate();
        if (mListener != null) {
            mListener.onParamChange();
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (int i = 0; i < mBeanList.size(); ++i) {
            EnlargerBean bean = mBeanList.get(i);
            int centerX = bean.getRect().centerX();
            int centerY = bean.getRect().centerY();
            if (!bean.isIsSelected()) {
                mPaint.setColor(mNormalPaintColor);
            } else {
                mPaint.setColor(mSelPaintColor);
                DLog.i("winn", "sel:" + bean.getRect());
            }
            canvas.drawCircle(centerX, centerY, bean.getRect().width() / 2, mPaint);
        }
    }

    public float getScale(int index) {
        if (index > mBeanList.size() - 1) {
            return 0f;
        }
        EnlargerBean bean = mBeanList.get(index);
        return bean.getScale();
    }

    public float getRadius(int index) {
        if (index > mBeanList.size() - 1) {
            return RADIU;
        }
        EnlargerBean bean = mBeanList.get(index);
        if (bean.getRect() != null) {
            return (float) bean.getRect().width() / 2 / getWidth();
        } else {
            return RADIU;
        }
    }

    public PointF getCenter(int index) {
        if (index > mBeanList.size() - 1) {
            return new PointF(CENTER_X, CENTER_Y);
        }
        EnlargerBean bean = mBeanList.get(index);
        if (bean.getRect() != null) {
            PointF center = new PointF((float) bean.getRect().centerX() / getWidth(),
                    (float) bean.getRect().centerY() / getHeight());
            return center;
        } else {
            return new PointF(CENTER_X, CENTER_Y);
        }
    }

    public OnParamChangeListener getListener() {
        return mListener;
    }

    public void setListener(OnParamChangeListener listener) {
        this.mListener = listener;
    }

    public interface OnParamChangeListener {
        void onParamChange();
    }
}
